home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Graphics Plus
/
Graphics Plus.iso
/
general
/
modelers
/
geomview
/
source.lha
/
Geomview
/
src
/
bin
/
stereo
/
stereo.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-11-09
|
15KB
|
602 lines
#include <stdio.h>
#include <forms.h>
#include <gl/gl.h>
#include <gl/device.h>
#include <gl/get.h>
#include <ooglutil.h>
#include <streampool.h>
#include <camera.h>
#include <window.h>
#include <lisp.h>
#include <sys/signal.h>
#include "sterui.h"
extern HandleOps CamOps, WindowOps;
static void monitor(int mode);
#define CURRENT 0
#define ST_MONO 1
#define ST_CROSSEYED 2
#define ST_HARDWARE 3
#define ST_COLORED 4
#define FOR_SOMETHING 0
#define FOR_FOCUS 1
#define FOR_REDRAW 2
Camera *cam;
WnWindow *win;
int camwinseq;
int expectredraw;
Pool *io;
Lake *lake;
long mainwin = -1, helpwin = -1, morewin = -1; /* GL window id's */
/* Values cached from current camera & window */
int isstereo = 0;
float pixelaspect = 1; /* pixel aspect */
float camaspect = 1.3; /* Camera aspect ratio, xsize/ysize */
float halffield = .4; /* half linear field (= tan(fov/2)) */
float halfyfield = .4; /* half Y-axis linear field */
float focallen = 3; /* focal length */
char *camname = "focus"; /* Use this camera */
int smode = ST_MONO; /* Last known mode */
WnPosition curpos;
int xsize, ysize;
/* Stereo convergence angle to an object in the nominal plane of view */
float halfconv = .1; /* tan(current convergence angle/2) */
float halfmaxconv = .22; /* tan(max allowable convergence/2) */
int swapeyes = 1;
/* Hardware parameters */
float pixperinch;
int xscreen, yscreen;
float screenwidth;
/* Warmware parameter? */
float ocularsep = 1.15; /* 2*ocularsep inches between human eyes */
current_mode()
{
if(cam == NULL || win == NULL) {
fprintf(stderr, "Hey? -- stereo sleeping...\n");
unqdevice(WINSHUT);
unqdevice(WINQUIT);
pause();
return ST_MONO;
}
CamGet(cam, CAM_STEREO, &isstereo);
CamGet(cam, CAM_HALFYFIELD, &halfyfield);
CamGet(cam, CAM_HALFFIELD, &halffield);
CamGet(cam, CAM_FOCUS, &focallen);
CamGet(cam, CAM_ASPECT, &camaspect);
WnGet(win, WN_PIXELASPECT, &pixelaspect);
WnGet(win, WN_CURPOS, &curpos);
xsize = curpos.xmax - curpos.xmin + 1;
ysize = curpos.ymax - curpos.ymin + 1;
return smode;
}
void
set_mode(int mode, int why)
{
char *layout = "no";
int stereo = 1;
int gap = 0;
int dx, hvpwidth;
float halfxfield, newxfield, newyfield, newfocallen, newaspect, focalscale;
int got;
char winstuff[80];
char camstuff[80];
char advice[120];
static int oldxsize = -1, oldysize;
request_camwin();
got = camwinseq;
do {
LFree( LEvalSexpr(lake) );
} while(got == camwinseq); /* Keep reading until we see a camera/window. */
got = current_mode();
if(mode == 0)
mode = got;
if(why == FOR_REDRAW && oldxsize == xsize && oldysize == ysize) {
expectredraw = 0;
return;
}
#ifdef notdef
fprintf(stderr, "# halfyfield %.3f halffield %.3f fov %.3f\r\n",
halfyfield, halffield, 2*DEGREES(atan(halffield)));
#endif
winstuff[0] = '\0';
camstuff[0] = '\0';
hvpwidth = xsize/2;
newyfield = halfyfield;
focalscale = 1;
printf("(progn\n");
switch(mode) {
case ST_MONO:
monitor(HZ60);
pixelaspect = 1;
layout = "no";
stereo = 0;
camaspect = (double)xsize / ysize;
newxfield = camaspect>1 ? camaspect*halffield : halffield;
break;
case ST_CROSSEYED:
monitor(HZ60);
hvpwidth = xsize/4;
dx = xsize/2;
pixelaspect = 1;
layout = "horizontal";
camaspect = .5*xsize / ysize;
/* Field-of-view is related to convergence angle in crosseyed view:
* tan(xfov/2) = tan(conv/2) / (1 + ocularsep/(viewportwidth/2)).
* Push the camera back so as to frame the same object, assuming its
* "focus" distance correctly reflects the object of interest.
*/
halfxfield = camaspect>1 ? halffield*camaspect : halffield;
newxfield = halfconv / (1 + ocularsep*pixperinch / hvpwidth);
focalscale = halfxfield / newxfield;
break;
case ST_HARDWARE:
monitor(STR_RECT);
gap = 40;
dx = 0;
pixelaspect = .5;
layout = "vertical";
sprintf(winstuff, "position %d %d %d %d\n",
curpos.xmin, curpos.xmax, 0, yscreen-1);
camaspect = (double)xsize / ((yscreen - gap) / 2);
halfxfield = camaspect>1 ? halffield*camaspect : halffield;
newxfield = halfconv / (pixelaspect * ocularsep*pixperinch / hvpwidth);
focalscale = halfxfield / newxfield;
break;
case ST_COLORED:
monitor(HZ60);
gap = 0;
dx = 0;
pixelaspect = 1;
layout = "colored";
camaspect = (double)xsize / ysize;
halfxfield = halfyfield*camaspect;
newxfield = halfconv / (ocularsep*pixperinch / hvpwidth);
focalscale = halfxfield / newxfield;
break;
default:
fprintf(stderr, "set_mode(%d)?\n", mode);
}
halfyfield = newxfield/camaspect;
halffield = newxfield < halfyfield ? newxfield : halfyfield;
newfocallen = focallen * focalscale;
#ifdef notdef
fprintf(stderr, "# NEW halfxfield %.3f halfyfield %.3f aspect %.3f focus %.2f fov %.3f hconv %.1f\r\n",
halfxfield, halfyfield, camaspect, newfocallen,
2*DEGREES(atan(halffield)), 2*DEGREES(atan(halfconv)));
#endif
if(fabs(focalscale - 1) > .02 && why == FOR_SOMETHING && !fl_get_button(FixedCamButton)) {
float near, far;
CamGet(cam, CAM_NEAR, &near);
CamGet(cam, CAM_FAR, &far);
printf("(transform %s self self translate 0 0 %g)\n",
camname, focallen - newfocallen);
sprintf(camstuff, "focus %g near %g far %g\n",
newfocallen, near*focalscale, far*focalscale);
focallen = newfocallen;
}
printf("(stereowin %s %s %d)\n", camname, layout, gap);
printf("(merge window %s { pixelaspect %g %s })\n",
camname, pixelaspect, winstuff);
printf("(merge camera %s {\n\
%s perspective 1 frameaspect %g halfyfield %g\n\
stereyes\n\
transform { 1 0 0 0 0 1 0 0 %g 0 1 0 %g 0 0 1 }\n\
transform { 1 0 0 0 0 1 0 0 %g 0 1 0 %g 0 0 1 }\n\
}))",
camname, camstuff, camaspect, halfyfield,
-swapeyes*halfconv, -swapeyes*halfconv*focallen,
swapeyes*halfconv, swapeyes*halfconv*focallen);
fflush(stdout);
/* Advise viewing from distance such that the field-of-view is correct. */
halfxfield = halffield * (camaspect>1 ? camaspect : 1);
sprintf(advice, "%.1f degree field of view\nBest view ~%.0f\" from screen",
2*DEGREES(atan(halffield)), hvpwidth/pixperinch / halfxfield);
fl_set_object_label(BestViewText, advice);
isstereo = stereo;
expectredraw = 1;
oldxsize = xsize;
oldysize = ysize;
if(stereo)
fl_show_object(SwapButton);
else
fl_hide_object(SwapButton);
if(fl_get_browser(StereoBrowser) != mode)
fl_select_browser_line(StereoBrowser, mode);
}
void
ConvProc(FL_OBJECT *obj, long arg)
{
float v = fl_get_slider_value(obj);
halfconv = tan(RADIANS(v/2));
if(isstereo)
set_mode(CURRENT, FOR_SOMETHING);
}
void
StereoProc(FL_OBJECT *obj, long arg)
{
set_mode(fl_get_browser(obj), FOR_SOMETHING);
}
void
SwapProc(FL_OBJECT *obj, long arg)
{
swapeyes = fl_get_button(obj) ? -1 : 1;
set_mode(CURRENT, FOR_SOMETHING);
}
LDEFINE(stereowin, LVOID, "")
{
char *cam = NULL, *mode = NULL;
LDECLARE(("stereowin", LBEGIN,
LSTRING, &cam,
LSTRING, &mode,
LREST, NULL,
LEND));
if(mode == NULL)
return Lnil;
switch(mode[0]) {
case 'n': smode = ST_MONO; break; /* "no" */
case 'h': smode = ST_CROSSEYED; break; /* "horizontal" */
case 'v': smode = ST_HARDWARE; break; /* "vertical" */
case 'c': smode = ST_COLORED; break; /* "colored" */
default:
fprintf(stderr,
"stereo: Can't understand '(stereowin %s %s)' from geomview.\n",
cam, mode);
}
return Lt;
}
LDEFINE(redraw, LVOID, "")
{
LDECLARE(("redraw", LBEGIN,
LREST, NULL,
LEND));
if(expectredraw-- <= 0) {
expectredraw = 1; /* Prevent reentrant calls */
set_mode(CURRENT, FOR_REDRAW);
}
return Lt;
}
static char simplepick[] = "(pick %s nil * nil nil nil nil nil nil nil)";
LDEFINE(pick, LVOID, "")
{
float z;
HPoint3 pt;
char *me, *it;
int npt = 4;
static int picking = 0;
LDECLARE(("pick", LBEGIN,
LSTRING, &me,
LSTRING, &it,
LHOLD, LARRAY, LFLOAT, &pt, &npt,
LREST, NULL,
LEND));
fl_set_object_boxtype(FocalButton, FL_UP_BOX);
if(picking) return Lnil;
picking = 1;
printf("(progn (uninterest\n");
printf(simplepick, camname);
printf(")");
if(npt == 4) {
printf("(merge camera %s { focus %g }))\n", camname, -pt.z / pt.w);
fflush(stdout);
set_mode(CURRENT, FOR_FOCUS);
} else {
printf(")\n"); /* Close the progn */
fflush(stdout);
}
picking = 0;
return Lt;
}
static char simplemerge[] = "(merge camera %s *)";
LDEFINE(merge, LVOID,
"(merge camera CAM-ID { CAMERA ... } )")
{
char *opsname = NULL;
int c, id;
LObject *kw = NULL, *idarg = NULL;
float newfocallen = focallen;
if (lake == NULL)
return Lt;
/* All the work of this function is done at parse time. */
/* parse first arg [ops]: */
if (! LakeMore(lake,c) || (kw = LSexpr(lake)) == Lnil ||
!LFROMOBJ(LSTRING)(kw, &opsname) || strcmp(opsname, "camera") != 0) {
OOGLSyntax(stdin, "merge: expected \"camera\", got \"%s\"", opsname);
goto parsefail;
}
/* parse 2nd arg; it's a string (id) */
if (! LakeMore(lake,c) || (idarg = LEvalSexpr(lake)) == Lnil) {
OOGLSyntax(stdin,"\"merge\": expected CAM-ID");
goto parsefail;
}
cam = NULL;
if(CamOps.strmin(POOL(lake), NULL, &cam) == 0) {
OOGLSyntax(stdin, "\"merge\": error reading camera");
goto parsefail;
}
CamGet(cam, CAM_FOCUS, &focallen);
if(fabs(focallen - newfocallen) > .01) {
focallen = newfocallen;
if(!expectredraw)
set_mode(CURRENT, FOR_FOCUS);
}
parsefail:
LFree(kw);
LFree(idarg);
return Lt;
}
request_camwin()
{
printf("\
(progn (echo (stereowin %s)) (echo \"(camwin \") (write camera - %s) (write window - %s) (echo \"\\n)\\n\") )\n",
camname, camname, camname);
fflush(stdout);
}
LDEFINE(camwin, LVOID, "")
{
if(lake == NULL) return Lt;
camwinseq++;
if(CamStreamIn(POOL(lake), NULL, &cam) <= 0) {
OOGLSyntax(stdin, "stereo: couldn't read camera");
return Lnil;
}
if(WnStreamIn(POOL(lake), NULL, &win) <= 0) {
OOGLSyntax(stdin, "stereo: couldn't read window");
return Lnil;
}
return Lt;
}
void
FocalProc(FL_OBJECT *obj, long arg)
{
printf("(interest ");
printf(simplepick, camname);
printf(")\n");
fflush(stdout);
fl_set_object_label(BestViewText, "Click right mouse on point");
fl_set_object_boxtype(obj, FL_DOWN_BOX);
}
static char *HelpText[] = {
#include "help.c"
};
void HelpProc(FL_OBJECT *obj, long arg)
{ helpwin = fl_show_form(Help, FL_PLACE_SIZE, TRUE, "Stereo Help"); }
int
validinput(FL_OBJECT *obj, float *val)
{
char *s = fl_get_input(obj);
char *s0 = s;
float v;
v = strtod(s, &s);
if(s == s0) return 0;
if(*val == v) return -1;
*val = v;
return 1;
}
void updateMore()
{
char s[80];
fl_freeze_form(More);
sprintf(s, "%.2f", screenwidth);
fl_set_input(ScreenWidthInput, s);
sprintf(s, "%.2f", 2*ocularsep);
fl_set_input(OcularInput, s);
fl_unfreeze_form(More);
}
void
OcularSepProc(FL_OBJECT *obj, long arg)
{
if(validinput(obj, &ocularsep) > 0) {
ocularsep *= .5;
set_mode(CURRENT, FOR_SOMETHING);
}
updateMore();
}
void
ScreenWidthProc(FL_OBJECT *obj, long arg)
{
if(validinput(obj, &screenwidth) > 0 && screenwidth > 0) {
pixperinch = xscreen / screenwidth;
set_mode(CURRENT, FOR_SOMETHING);
}
updateMore();
}
void
CamNameProc(FL_OBJECT *obj, long arg)
{
char *is = fl_get_input(CamNameInput);
if(strcmp(camname, is) && is[0] != '\0') {
camname = is;
request_camwin();
}
}
void MoreProc(FL_OBJECT *obj, long arg)
{
updateMore();
morewin = fl_show_form(More, FL_PLACE_SIZE, TRUE, "Stereo Parameters");
}
static void
monitor(int mode)
{
if((mode == STR_RECT) != (getmonitor() == STR_RECT) && !getenv("NOMON"))
setmonitor(mode);
}
void
die(int sig)
{
monitor(HZ60);
exit(0);
}
void
QuitProc(FL_OBJECT *obj, long arg)
{
die(0);
}
void
DoneProc(FL_OBJECT *obj, long arg)
{
fl_hide_form(obj->form);
}
main(int argc, char *argv[])
{
int i, c;
io = PoolStreamOpen("stdio", stdin, 0, &CamOps);
PoolStreamOpen("stdio", stdout, 1, &CamOps);
lake = LakeDefine(stdin, stdout, io);
LInit();
LDefun("pick", Lpick, Hpick);
LDefun("redraw", Lredraw, Hredraw);
LDefun("merge", Lmerge, Hmerge);
LDefun("camwin", Lcamwin, Hcamwin);
LDefun("stereowin", Lstereowin, Hstereowin);
foreground();
fl_init();
create_the_forms();
signal(SIGHUP, die);
signal(SIGINT, die);
/* This order must match that of the ST_* define's */
fl_add_browser_line(StereoBrowser, "Monoscopic");
fl_add_browser_line(StereoBrowser, "Crosseyed");
fl_add_browser_line(StereoBrowser, "Hardware");
fl_add_browser_line(StereoBrowser, "Red/Cyan");
fl_set_slider_bounds(ConvSlider, 1.5, DEGREES(atan(halfmaxconv)));
fl_set_slider_value(ConvSlider, 2*DEGREES(atan(halfconv)));
mainwin = fl_show_form(stereo, FL_PLACE_SIZE, TRUE, "Stereo View");
fl_qdevice(WINSHUT);
fl_qdevice(WINQUIT);
fl_set_input(CamNameInput, camname);
for(i = 0; i < COUNT(HelpText); i++)
fl_add_browser_line(HelpBrowser, HelpText[i]);
/* Screen pixel density */
xscreen = getgdesc(GD_XPMAX);
yscreen = getgdesc(GD_YPMAX);
screenwidth = getgdesc(GD_XMMAX) * .03937;
pixperinch = xscreen / screenwidth;
printf("(interest (redraw))\n");
printf("(interest (merge camera))\n");
request_camwin();
for(i = 1; i < argc; i++) {
if(!strcmp(argv[i], "-fixed")) {
fl_set_button(FixedCamButton, 1);
} else if(!strcmp(argv[i], "-unfixed")) {
fl_set_button(FixedCamButton, 0);
} else if(!strncmp(argv[i], "-cam", 4)) { /* -cam or -camera */
fl_set_input(CamNameInput, argv[++i]);
CamNameProc(CamNameInput, 0);
} else if(!strcmp(argv[i], "-mode")) {
/* ... */
}
}
for(;;) {
if((c = async_fnextc(stdin, 0)) == NODATA) {
static struct timeval tenth = { 0, 100000 }; /* 0.1 sec */
select(0, NULL, NULL, NULL, &tenth);
} else {
/* Got a Lisp expression */
c = camwinseq;
LFree(LEvalSexpr(lake));
/* If it was a camera/window pair, ... */
if(c != camwinseq)
set_mode(current_mode(), FOR_REDRAW);
}
fl_check_forms();
if(fl_qtest()) {
short v;
switch( fl_qread(&v) ) {
case WINQUIT:
die(0);
case WINSHUT:
if(v == mainwin) die(0);
else if(v == helpwin) fl_hide_form(Help), helpwin = -1;
else if(v == morewin) fl_hide_form(More), morewin = -1;
}
}
}
}